/**
 * Date:2017年10月31日下午3:26:33
 * Copyright (c) 2017, www.bwbroad.com All Rights Reserved.
 *
 */

package ssh;

import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;

/**
 * Description: 命令解释器 <br/>
 * Date: 2017年10月31日 下午3:26:33 <br/>
 * 
 * @author xuejianxin
 */
public class CmdTool {
	// 命令类型
	private enum CMD_TYPE {
		CMD, UPLOAD, DOWNLOAD, CONFIG
	};

	// 分割命令参数
	private static final String CMD_PARAMETER_SPLIT = ",";
	// 分割命令
	private static final String CMD_SPLIT = "#";
	// 命令注释行
	private static final String COMENTS_LINE_FLAG = "#";
	public static final Charset DEFAULT_CHARSET = Charset.forName("utf-8");

	private CmdTool() {
		// TODO 防止初始化
	}

	/**
	 * 
	 * Description:解释并执行配置文件<br/>
	 * Date: 2017年11月3日 下午3:53:57 <br/>
	
	 * @author xuejianxin
	 * @param cmdFile
	 * @throws Exception
	 */
	public static void parserAndExecute(String cmdFile) throws Exception {
		// 读取配置
		List<String> cmdStrs = IOUtils.readLines(new FileInputStream(new File(cmdFile)), DEFAULT_CHARSET);
		parserAndExecute(cmdStrs);
	}
	
	/**
	 * 
	 * Description:解释并执行br/> Date: 2017年10月31日 下午4:28:31 <br/>
	 * 
	 * @author xuejianxin
	 * @param cmdFile
	 * @param remoteShellExecutor
	 * @throws Exception
	 */
	public static void parserAndExecute(List<String> cmdList ) throws Exception {
		// 保存所有有效命令
		List<AbstractCmd> cmds = new ArrayList<AbstractCmd>();
		// 保存主机的连接ip,用户和密码
		CmdConfig config = null;
		AbstractCmd cmd = null;
		int lineNum = 1;
		for (String s : cmdList) {
			lineNum++;
			if (!s.startsWith(COMENTS_LINE_FLAG) && null != s
					&& !"".equals(s.trim())) {// 跳过注释行和空白行
				// 分割命令
				String[] oneCmd = s.split(CMD_SPLIT);
				assert oneCmd.length >= 2;
				// 读取命令类型
				CMD_TYPE cmdType = CMD_TYPE.valueOf(oneCmd[0].trim()
						.toUpperCase());
				String cmdContent = oneCmd[1].trim();
				switch (cmdType) {
				case CMD:
					cmd = new Cmd(cmdType, cmdContent);
					cmds.add(cmd);
					break;
				case UPLOAD:
					cmd = new CmdUpload(cmdType, cmdContent);
					cmds.add(cmd);
					break;
				case DOWNLOAD:
					cmd = new CmdDownload(cmdType, cmdContent);
					cmds.add(cmd);
					break;
				case CONFIG:
					// 配置命令不需要执行
					config = new CmdConfig(cmdType, cmdContent);
					break;
				default:
					throw new RuntimeException(String.format("第%d行命令无法解释\n",
							lineNum));
				}

			}

		}
		if (null != config && !cmds.isEmpty()) {
			String[] configs = config.getCmdContent()
					.split(CMD_PARAMETER_SPLIT);
			assert 3 == configs.length;
			RemoteShellExecutor executor = new RemoteShellExecutor(
					configs[0].trim(), configs[1].trim(), configs[2].trim());
			// 执行命令
			execute(executor, cmds);
			// 关闭
			executor.closeConn();
		}
	}

	/**
	 * 
	 * Description:执行命令<br/>
	 * Date: 2017年10月31日 下午4:28:47 <br/>
	 * 
	 * @author xuejianxin
	 * @param remoteShellExecutor
	 * @param cmds
	 * @throws Exception
	 */
	private static void execute(RemoteShellExecutor remoteShellExecutor,
			List<AbstractCmd> cmds) throws Exception {
		for (AbstractCmd cmd : cmds) {
			System.out.println(cmd);
			cmd.setRemoteShellExecutor(remoteShellExecutor);
			cmd.execute();
		}
	}

	/**
	 * 
	 * Description: 命令基类 <br/>
	 * Date: 2017年10月31日 下午5:35:00 <br/>
	 *
	 * @author xuejianxin
	 */
	private static abstract class AbstractCmd {
		// 执行引擎
		protected RemoteShellExecutor remoteShellExecutor;
		// 命令类型
		protected CMD_TYPE cmdType;
		// 命令内容
		protected String cmdContent;

		public AbstractCmd(CMD_TYPE cmdType, String cmdContent) {
			this.cmdType = cmdType;
			this.cmdContent = cmdContent;
		}

		/**
		 * 
		 * Description:执行命令 子类需要覆盖此方法<br/>
		 * Date: 2017年10月31日 下午5:35:52 <br/>
		 * 
		 * @author xuejianxin
		 * @return
		 * @throws Exception
		 */
		public abstract int execute() throws Exception;

		public CMD_TYPE getCmdType() {
			return cmdType;
		}

		public String getCmdContent() {
			return cmdContent;
		}

		public void setRemoteShellExecutor(
				RemoteShellExecutor remoteShellExecutor) {
			this.remoteShellExecutor = remoteShellExecutor;
		}

		@Override
		public String toString() {
			return String.format("CMD [cmdType=%s, cmdContent=%s]", cmdType,
					cmdContent);
		}

	}

	/**
	 * 
	 * Description: 普通shell命令<br/>
	 * Date: 2017年10月31日 下午3:52:11 <br/>
	 *
	 * @author xuejianxin
	 */
	private static class Cmd extends AbstractCmd {
		public Cmd(CMD_TYPE cmdType, String cmdContent) {
			super(cmdType, cmdContent);
		}

		@Override
		public int execute() throws Exception {
			return remoteShellExecutor.exec(this.cmdContent);
		}

	}

	/**
	 * 
	 * Description: 上传命令 <br/>
	 * Date: 2017年10月31日 下午5:28:35 <br/>
	 *
	 * @author xuejianxin
	 */
	private static class CmdUpload extends AbstractCmd {
		public CmdUpload(CMD_TYPE cmdType, String cmdContent) {
			super(cmdType, cmdContent);
		}

		@Override
		public int execute() throws Exception {
			String[] cmds = this.cmdContent.split(CmdTool.CMD_PARAMETER_SPLIT);
			assert 2 == cmds.length;
			return remoteShellExecutor.uploadFile(cmds[0], cmds[1]);
		}

	}

	/**
	 * 
	 * Description: 下载命令 <br/>
	 * Date: 2017年10月31日 下午5:28:49 <br/>
	 *
	 * @author xuejianxin
	 */
	private static class CmdDownload extends AbstractCmd {
		public CmdDownload(CMD_TYPE cmdType, String cmdContent) {
			super(cmdType, cmdContent);
		}

		@Override
		public int execute() throws Exception {
			String[] cmds = this.cmdContent.split(CmdTool.CMD_PARAMETER_SPLIT);
			assert 2 == cmds.length;
			return remoteShellExecutor.downloadFile(cmds[0], cmds[1]);
		}

	}

	/**
	 * 
	 * Description: 配置命令 <br/>
	 * Date: 2017年10月31日 下午5:28:58 <br/>
	 *
	 * @author xuejianxin
	 */
	private static class CmdConfig extends AbstractCmd {
		public CmdConfig(CMD_TYPE cmdType, String cmdContent) {
			super(cmdType, cmdContent);
		}

		@Override
		public int execute() throws Exception {
			throw new Exception("配置命令不能执行");
		}
	}

}
